home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DJGPP / DJ111M2.ZIP / go32 / ed / syms.c
C/C++ Source or Header  |  1994-01-09  |  17KB  |  758 lines

  1. /* This is file SYMS.C */
  2. /*
  3. ** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
  4. **
  5. ** This file is distributed under the terms listed in the document
  6. ** "copying.dj", available from DJ Delorie at the address above.
  7. ** A copy of "copying.dj" should accompany this file; if not, a copy
  8. ** should be available from where this file was obtained.  This file
  9. ** may not be distributed without a verbatim copy of "copying.dj".
  10. **
  11. ** This file is distributed WITHOUT ANY WARRANTY; without even the implied
  12. ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. */
  14.  
  15. #include <stdio.h>
  16. #include <fcntl.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <ctype.h>
  20. #include <dos.h>
  21. #include <io.h>
  22.  
  23. #include "ed.h"
  24. #include "coff.h"
  25. #include "syms.h"
  26. #include "stab.h"
  27.  
  28. #define DO_SYMS 1
  29.  
  30. int undefined_symbol=0;
  31.  
  32. #define Ofs(n) ((int)&(((TSS *)0)->n))
  33.  
  34. struct {
  35.   char *name;
  36.   int size;
  37.   int ofs;
  38.   } regs[] = {
  39.   "%eip", 4, Ofs(tss_eip),
  40.   "%eflags", 4, Ofs(tss_eflags),
  41.   "%eax", 4, Ofs(tss_eax),
  42.   "%ebx", 4, Ofs(tss_ebx),
  43.   "%ecx", 4, Ofs(tss_ecx),
  44.   "%edx", 4, Ofs(tss_edx),
  45.   "%esp", 4, Ofs(tss_esp),
  46.   "%ebp", 4, Ofs(tss_ebp),
  47.   "%esi", 4, Ofs(tss_esi),
  48.   "%edi", 4, Ofs(tss_edi),
  49.   "%ax", 2, Ofs(tss_eax),
  50.   "%bx", 2, Ofs(tss_ebx),
  51.   "%cx", 2, Ofs(tss_ecx),
  52.   "%dx", 2, Ofs(tss_edx),
  53.   "%ah", 1, Ofs(tss_eax)+1,
  54.   "%bh", 1, Ofs(tss_ebx)+1,
  55.   "%ch", 1, Ofs(tss_ecx)+1,
  56.   "%dh", 1, Ofs(tss_edx)+1,
  57.   "%al", 1, Ofs(tss_eax),
  58.   "%bl", 1, Ofs(tss_ebx),
  59.   "%cl", 1, Ofs(tss_ecx),
  60.   "%dl", 1, Ofs(tss_edx),
  61.   0, 0, 0
  62. };
  63.  
  64. #if !DO_SYMS
  65.  
  66. void syms_init(char *fname) {}
  67. void syms_list(int byval) {}
  68. void syms_listwild(char *pattern) {}
  69.  
  70. word32 syms_name2val(char *name)
  71. {
  72.   if (isdigit(name[0]))
  73.   {
  74.     int v;
  75.     if (strncmp(name, "0x", 2) == 0)
  76.       sscanf(name+2, "%x", &v);
  77.     else
  78.       sscanf(name, "%d", &v);
  79.     undefined_symbol = 0;
  80.     return v;
  81.   }
  82.   else
  83.   {
  84.     undefined_symbol = 1;
  85.     return 0;
  86.   }
  87. }
  88.  
  89. char *syms_val2name(word32 val, word32 *delta)
  90. {
  91.   static char noname_buf[20];
  92.   sprintf(noname_buf, "%#lx", val);
  93.   *delta = 0;
  94.   return noname_buf;
  95. }
  96.  
  97. char *syms_val2line(word32 val, int *lineret, int exact)
  98. {
  99.   return 0;
  100. }
  101.  
  102. #else
  103.  
  104. /* From the file */
  105.  
  106. typedef struct SYM_ENTRY {
  107.   word32 string_off;
  108.   word8 type;
  109.   word8 other;
  110.   word16 desc;
  111.   word32 val;
  112. } SYM_ENTRY;
  113.  
  114. static FILHDR f_fh;
  115. static AOUTHDR f_ah;
  116. static SCNHDR *f_sh;
  117. static SYMENT *f_symtab;
  118. static SYM_ENTRY *f_aoutsyms;
  119. static AUXENT *f_aux;
  120. static LINENO **f_lnno;
  121. static char *f_string_table;
  122. static char *f_types;
  123.  
  124. /* built internally */
  125.  
  126. typedef struct {
  127.   char *filename;
  128.   word32 first_address;
  129.   word32 last_address;
  130.   LINENO *lines;
  131.   int num_lines;
  132. } FileNode;
  133.  
  134. static FileNode *files;
  135. static int num_files;
  136.  
  137. typedef struct SymNode {
  138.   char *name;
  139.   word32 address;
  140.   char type_c;
  141. } SymNode;
  142.  
  143. static SymNode *syms;
  144. static SymNode *syms_byname;
  145. static int num_syms;
  146.  
  147. static int syms_sort_bn(const void *a, const void *b)
  148. {
  149.   SymNode *sa = (SymNode *)a;
  150.   SymNode *sb = (SymNode *)b;
  151.   return strcmp(sa->name, sb->name);
  152. }
  153.  
  154. static int syms_sort_bv(const void *a, const void *b)
  155. {
  156.   SymNode *sa = (SymNode *)a;
  157.   SymNode *sb = (SymNode *)b;
  158.   return sa->address - sb->address;
  159. }
  160.  
  161. static char *symndup(char *s, int len)
  162. {
  163.   char c = s[len], *rv;
  164.   s[len] = 0;
  165.   rv = strdup(s);
  166.   s[len] = c;
  167.   return rv;
  168. }
  169.  
  170. static int valid_symbol(int i)
  171. {
  172.   char *sn;
  173.   if (f_symtab[i].e.e.e_zeroes)
  174.     sn = f_symtab[i].e.e_name; 
  175.   else
  176.     sn = f_string_table + f_symtab[i].e.e.e_offset;
  177.   if (sn[0] != '_')
  178.     return 0;
  179.   if (strncmp(sn, "___gnu_compiled", 15) == 0)
  180.     return 0;
  181.   if (strcmp(sn, "__DYNAMIC") == 0)
  182.     return 0;
  183.   return 1;
  184. }
  185.  
  186. static void process_coff(FILE *fd, long ofs)
  187. {
  188.   int i, f, s, f_pending;
  189.   LINENO *l;
  190.   int l_pending;
  191.   word32 strsize;
  192.   char *name;
  193.  
  194.   fseek(fd, ofs, 0);
  195.   fread(&f_fh, 1, FILHSZ, fd);
  196.   fread(&f_ah, 1, AOUTSZ, fd);
  197.   f_sh = (SCNHDR *)malloc(f_fh.f_nscns * SCNHSZ);
  198.   f_types = (char *)malloc(f_fh.f_nscns);
  199.   f_lnno = (LINENO **)malloc(f_fh.f_nscns * sizeof(LINENO *));
  200.   fread(f_sh, f_fh.f_nscns, SCNHSZ, fd);
  201.  
  202.   for (i=0; i<f_fh.f_nscns; i++)
  203.   {
  204.     if (f_sh[i].s_flags & STYP_TEXT)
  205.       f_types[i] = 'T';
  206.     if (f_sh[i].s_flags & STYP_DATA)
  207.       f_types[i] = 'D';
  208.     if (f_sh[i].s_flags & STYP_BSS)
  209.       f_types[i] = 'B';
  210.     if (f_sh[i].s_nlnno)
  211.     {
  212.       fseek(fd, ofs + f_sh[i].s_lnnoptr, 0L);
  213.       f_lnno[i] = (LINENO *)malloc(f_sh[i].s_nlnno * LINESZ);
  214.       fread(f_lnno[i], LINESZ, f_sh[i].s_nlnno, fd);
  215.     }
  216.     else
  217.       f_lnno[i] = 0;
  218.   }
  219.  
  220.   fseek(fd, ofs + f_fh.f_symptr + f_fh.f_nsyms * SYMESZ, 0);
  221.   fread(&strsize, 1, 4, fd);
  222.   f_string_table = (char *)malloc(strsize);
  223.   fread(f_string_table+4, 1, strsize-4, fd);
  224.   f_string_table[0] = 0;
  225.  
  226.   fseek(fd, ofs+f_fh.f_symptr, 0);
  227.   f_symtab = (SYMENT *)malloc(f_fh.f_nsyms * SYMESZ);
  228.   fread(f_symtab, SYMESZ, f_fh.f_nsyms, fd);
  229.   f_aux = (AUXENT *)f_symtab;
  230.  
  231.   num_syms = num_files = 0;
  232.   for (i=0; i<f_fh.f_nsyms; i++)
  233.   {
  234.     switch (f_symtab[i].e_sclass)
  235.     {
  236.       case C_FILE:
  237.         num_files++;
  238.         break;
  239.       case C_EXT:
  240.       case C_STAT:
  241.         if (!valid_symbol(i))
  242.           break;
  243.         num_syms++;
  244.         break;
  245.     }
  246.     i += f_symtab[i].e_numaux;
  247.   }
  248.  
  249.   files = (FileNode *)malloc(num_files * sizeof(FileNode));
  250.  
  251.   syms = (SymNode *)malloc(num_syms * sizeof(SymNode));
  252.  
  253.   f = s = f_pending = l_pending = 0;
  254.   for (i=0; i<f_fh.f_nsyms; i++)
  255.   {
  256.     switch (f_symtab[i].e_sclass)
  257.     {
  258.       case C_FILE:
  259.         if (f_aux[i+1].x_file.x_n.x_zeroes)
  260.           files[f].filename = symndup(f_aux[i+1].x_file.x_fname, 16);
  261.         else
  262.           files[f].filename = f_string_table + f_aux[i+1].x_file.x_n.x_offset;
  263.         files[f].lines = 0;
  264.         f_pending = 1;
  265.     f++;
  266.         break;
  267.       case C_EXT:
  268.       case C_STAT:
  269.  
  270.         if (f_symtab[i].e.e.e_zeroes)
  271.           name = f_symtab[i].e.e_name;
  272.         else
  273.           name = f_string_table + f_symtab[i].e.e.e_offset;
  274.  
  275.         if (f_pending && strcmp(name, ".text") == 0)
  276.         {
  277.           files[f-1].first_address = f_symtab[i].e_value;
  278.           files[f-1].last_address = f_symtab[i].e_value + f_aux[i+1].x_scn.x_scnlen - 1;
  279.           files[f-1].num_lines = f_aux[i+1].x_scn.x_nlinno;
  280.           f_pending = 0;
  281.         }
  282.  
  283.         if (ISFCN(f_symtab[i].e_type))
  284.         {
  285.           int scn = f_symtab[i].e_scnum - 1;
  286.           l = f_lnno[scn] + ((f_aux[i+1].x_sym.x_fcnary.x_fcn.x_lnnoptr - f_sh[scn].s_lnnoptr)/LINESZ);
  287.           l_pending = 1;
  288.           l->l_addr.l_paddr = f_symtab[i].e_value;
  289.         }
  290.  
  291.         if (!valid_symbol(i))
  292.           break;
  293.  
  294.         syms[s].address = f_symtab[i].e_value;
  295.         if (f_symtab[i].e.e.e_zeroes)
  296.           syms[s].name = symndup(f_symtab[i].e.e_name, 8);
  297.         else
  298.           syms[s].name = f_string_table + f_symtab[i].e.e.e_offset;
  299.         
  300.         switch (f_symtab[i].e_scnum)
  301.         {
  302.           case 1 ... 10:
  303.             syms[s].type_c = f_types[f_symtab[i].e_scnum-1];
  304.             break;
  305.           case N_UNDEF:
  306.             syms[s].type_c = 'U';
  307.             break;
  308.           case N_ABS:
  309.             syms[s].type_c = 'A';
  310.             break;
  311.           case N_DEBUG:
  312.             syms[s].type_c = 'D';
  313.             break;
  314.         }
  315.         if (f_symtab[i].e_sclass == C_STAT)
  316.           syms[s].type_c += 'a' - 'A';
  317.  
  318.         s++;
  319.         break;
  320.       case C_FCN:
  321.         if (f_pending && files[f-1].lines == 0)
  322.         {
  323.           files[f-1].lines = l;
  324.         }
  325.         if (l_pending)
  326.         {
  327.           int lbase = f_aux[i+1].x_sym.x_misc.x_lnsz.x_lnno - 1;
  328.           int i2;
  329.           l->l_lnno = lbase;
  330.           l++;
  331.           for (i2=0; l[i2].l_lnno; i2++)
  332.             l[i2].l_lnno += lbase;
  333.           l_pending = 0;
  334.         }
  335.         break;
  336.     }
  337.     i += f_symtab[i].e_numaux;
  338.   }
  339. }
  340.  
  341. static void process_aout(FILE *fd, long ofs)
  342. {
  343.   GNU_AOUT header;
  344.   word32 string_table_length;
  345.   int nsyms, i, f, s, l;
  346.  
  347.   fseek(fd, ofs, 0);
  348.   fread(&header, 1, sizeof(header), fd);
  349.  
  350.   fseek(fd, ofs + sizeof(header) + header.tsize + header.dsize + header.txrel + header.dtrel, 0);
  351.   nsyms = header.symsize / sizeof(SYM_ENTRY);
  352.   f_aoutsyms = (SYM_ENTRY *)malloc(header.symsize);
  353.   fread(f_aoutsyms, 1, header.symsize, fd);
  354.  
  355.   fread(&string_table_length, 1, 4, fd);
  356.   f_string_table = (char *)malloc(string_table_length);
  357.   fread(f_string_table+4, 1, string_table_length-4, fd);
  358.   f_string_table[0] = 0;
  359.  
  360.   num_files = num_syms = 0;
  361.   for (i=0; i<nsyms; i++)
  362.   {
  363.     char *symn = f_string_table + f_aoutsyms[i].string_off;
  364.     char *cp;
  365.     switch (f_aoutsyms[i].type & ~N_EXT)
  366.     {
  367.       case N_SO:
  368.         if (symn[strlen(symn)-1] == '/')
  369.           break;
  370.         num_files++;
  371.         break;
  372.       case N_TEXT:
  373.         cp = symn + strlen(symn) - 2;
  374.     if (strncmp(symn, "___gnu", 6) == 0 ||
  375.         strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ ||
  376.         strcmp(cp, ".o") == 0)
  377.       break;
  378.       case N_DATA:
  379.       case N_ABS:
  380.       case N_BSS:
  381.       case N_FN:
  382.       case N_SETV:
  383.       case N_SETA:
  384.       case N_SETT:
  385.       case N_SETD:
  386.       case N_SETB:
  387.       case N_INDR:
  388.         num_syms ++;
  389.         break;
  390.     }
  391.   }
  392.   
  393.   syms = (SymNode *)malloc(num_syms * sizeof(SymNode));
  394.   memset(syms, num_syms * sizeof(SymNode), 0);
  395.   files = (FileNode *)malloc(num_files * sizeof(FileNode));
  396.   memset(files, num_files * sizeof(FileNode), 0);
  397.  
  398.   f = s = 0;
  399.   for (i=0; i<nsyms; i++)
  400.   {
  401.     char c, *cp;
  402.     char *symn = f_string_table + f_aoutsyms[i].string_off;
  403.     switch (f_aoutsyms[i].type & ~N_EXT)
  404.     {
  405.       case N_SO:
  406.         if (symn[strlen(symn)-1] == '/')
  407.           break;
  408.         if (f && files[f-1].last_address == 0)
  409.           files[f-1].last_address = f_aoutsyms[i].val - 1;
  410.         files[f].filename = symn;
  411.         files[f].first_address = f_aoutsyms[i].val;
  412.         f ++;
  413.         break;
  414.       case N_SLINE:
  415.         files[f-1].num_lines++;
  416.         break;
  417.       case N_TEXT:
  418.         cp = symn + strlen(symn) - 2;
  419.     if (strncmp(symn, "___gnu", 6) == 0 ||
  420.         strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ ||
  421.         strcmp(cp, ".o") == 0)
  422.         {
  423.           if (f && files[f-1].last_address == 0)
  424.             files[f-1].last_address = f_aoutsyms[i].val - 1;
  425.           break;
  426.         }
  427.     c = 't';
  428.     goto sym_c;
  429.       case N_DATA:
  430.     c = 'd';
  431.     goto sym_c;
  432.       case N_ABS:
  433.     c = 'a';
  434.     goto sym_c;
  435.       case N_BSS:
  436.     c = 'b';
  437.     goto sym_c;
  438.       case N_FN:
  439.     c = 'f';
  440.     goto sym_c;
  441.       case N_SETV:
  442.     c = 'v';
  443.     goto sym_c;
  444.       case N_SETA:
  445.     c = 'v';
  446.     goto sym_c;
  447.       case N_SETT:
  448.     c = 'v';
  449.     goto sym_c;
  450.       case N_SETD:
  451.     c = 'v';
  452.     goto sym_c;
  453.       case N_SETB:
  454.     c = 'v';
  455.     goto sym_c;
  456.       case N_INDR:
  457.     c = 'i';
  458.     sym_c:
  459.         syms[s].name = symn;
  460.         syms[s].address = f_aoutsyms[i].val;
  461.         syms[s].type_c = (f_aoutsyms[i].type & N_EXT) ? (c+'A'-'a') : c;
  462.         s ++;
  463.         break;
  464.     }
  465.   }
  466.   
  467.   l = f = 0;
  468.   for (i=0; i<nsyms; i++)
  469.   {
  470.     char c, *cp;
  471.     char *symn = f_string_table + f_aoutsyms[i].string_off;
  472.     switch (f_aoutsyms[i].type & ~N_EXT)
  473.     {
  474.       case N_SO:
  475.         if (symn[strlen(symn)-1] == '/')
  476.           break;
  477.         files[f].lines = (LINENO *)malloc(files[f].num_lines * sizeof(LINENO));
  478.         f++;
  479.         l = 0;
  480.         break;
  481.       case N_SLINE:
  482.         files[f-1].lines[l].l_addr.l_paddr = f_aoutsyms[i].val;
  483.         files[f-1].lines[l].l_lnno = f_aoutsyms[i].desc;
  484.         l ++;
  485.         break;
  486.     }
  487.   }
  488.   
  489. }
  490.  
  491. static void process_file(FILE *fd, long ofs)
  492. {
  493.   short s, exe[2];
  494.   fseek(fd, ofs, 0);
  495.   fread(&s, 1, 2, fd);
  496.   switch (s)
  497.   {
  498.     case 0x5a4d:    /* .exe */
  499.       fread(exe, 2, 2, fd);
  500.       ofs += (long)exe[1] * 512L;
  501.       if (exe[0])
  502.         ofs += (long)exe[0] - 512L;
  503.       process_file(fd, ofs);
  504.       break;
  505.     case 0x014c:    /* .coff */
  506.       process_coff(fd, ofs);
  507.       break;
  508.     case 0x010b:    /* a.out ZMAGIC */
  509.     case 0x0107:    /* a.out object */
  510.       process_aout(fd, ofs);
  511.       break;
  512.   }
  513. }
  514.  
  515. void syms_init(char *fname)
  516. {
  517.   FILE *fd = fopen(fname, "rb");
  518.   if (fd == 0)
  519.   {
  520.     perror(fname);
  521.   }
  522.   else
  523.   {
  524.     process_file(fd, 0);
  525.  
  526.     syms_byname = (SymNode *)malloc(num_syms * sizeof(SymNode));
  527.     memcpy(syms_byname, syms, num_syms * sizeof(SymNode));
  528.     qsort(syms_byname, num_syms, sizeof(SymNode), syms_sort_bn);
  529.     qsort(syms, num_syms, sizeof(SymNode), syms_sort_bv);
  530.  
  531.     fclose(fd);
  532.   }
  533. }
  534.  
  535. int lookup_sym_byname(char *name, int idx, int ofs)
  536. {
  537.   int below, above;
  538.   char ch = name[idx];
  539.   name[idx] = 0;
  540.   
  541.   below = -1;
  542.   above = num_syms;
  543.   while (above - below > 1)
  544.   {
  545.     int mid = (above + below) / 2;
  546.     int c = 0;
  547.     if (ofs)
  548.       c = '_' - syms_byname[mid].name[0];
  549.     if (c == 0)
  550.       c = strcmp(name, syms_byname[mid].name+ofs);
  551.     if (c == 0)
  552.     {
  553.       name[idx] = ch;
  554.       return mid;
  555.     }
  556.     if (c < 0)
  557.       above = mid;
  558.     else
  559.       below = mid;
  560.   }
  561.   name[idx] = ch;
  562.   return -1;
  563. }
  564.  
  565. word32 syms_name2val(char *name)
  566. {
  567.   int cval, idx, sign=1, i;
  568.   word32 v;
  569.   char *cp;
  570.  
  571.   undefined_symbol = 0;
  572.  
  573.   idx = 0;
  574.   sscanf(name, "%s", name);
  575.  
  576.   if (name[0] == 0)
  577.     return 0;
  578.  
  579.   if (name[0] == '-')
  580.   {
  581.     sign = -1;
  582.     name++;
  583.   }
  584.   else if (name[0] == '+')
  585.   {
  586.     name++;
  587.   }
  588.   if (isdigit(name[0]))
  589.   {
  590.     if (sign == -1)
  591.       return -strtol(name, 0, 0);
  592.     return strtol(name, 0, 0);
  593.   }
  594.  
  595.   cp = strpbrk(name, "+-");
  596.   if (cp)
  597.     idx = cp-name;
  598.   else
  599.     idx = strlen(name);
  600.  
  601.   if (name[0] == '%') /* register */
  602.   {
  603.     for (i=0; regs[i].name; i++)
  604.       if (strncmp(name, regs[i].name, idx) == 0)
  605.       {
  606.     switch (regs[i].size)
  607.     {
  608.       case 1:
  609.         v = *(word8 *)((word8 *)(&a_tss) + regs[i].ofs);
  610.         break;
  611.       case 2:
  612.         v = *(word16 *)((word8 *)(&a_tss) + regs[i].ofs);
  613.         break;
  614.       case 4:
  615.         v = *(word32 *)((word8 *)(&a_tss) + regs[i].ofs);
  616.         break;
  617.     }
  618.     return v + syms_name2val(name+idx);
  619.       }
  620.   }
  621.  
  622.   for (i=0; i<idx; i++)
  623.     if (name[i] == '#')
  624.     {
  625.       int f;
  626.       int lnum, l;
  627.       sscanf(name+i+1, "%d", &lnum);
  628.       for (f=0; f<num_files; f++)
  629.       {
  630.     if ((strncmp(name, files[f].filename, i) == 0) && (files[f].filename[i] == 0))
  631.     {
  632.       for (l=0; l<files[f].num_lines; l++)
  633.       {
  634.         if (files[f].lines[l].l_lnno == lnum)
  635.           return files[f].lines[l].l_addr.l_paddr + syms_name2val(name+idx);
  636.       }
  637.       printf("undefined line number %.*s\n", idx, name);
  638.       undefined_symbol = 1;
  639.       return 0;
  640.     }
  641.       }
  642.       printf("Undefined file name %.*s\n", i, name);
  643.       undefined_symbol = 1;
  644.       return 0;
  645.     }
  646.  
  647.   i = lookup_sym_byname(name, idx, 0);
  648.   if (i == -1)
  649.     i = lookup_sym_byname(name, idx, 1);
  650.   if (i != -1)
  651.     return syms_byname[i].address * sign + syms_name2val(name+idx);
  652.   printf("Undefined symbol %.*s\n", idx, name);
  653.   undefined_symbol = 1;
  654.   return 0;
  655. }
  656.  
  657. static char noname_buf[11];
  658.  
  659. char *syms_val2name(word32 val, word32 *delta)
  660. {
  661.   static char buf[1000];
  662.   int above, below, mid;
  663.  
  664.   if (delta)
  665.     *delta = 0;
  666.  
  667.   if (num_syms <= 0)
  668.     goto noname;  
  669.   above = num_syms;
  670.   below = -1;
  671.   while (above-below > 1)
  672.   {
  673.     mid = (above+below)/2;
  674.     if (syms[mid].address == val)
  675.       break;
  676.     if (syms[mid].address > val)
  677.       above = mid;
  678.     else
  679.       below = mid;
  680.   }
  681.   if (syms[mid].address > val)
  682.   {
  683.     if (mid == 0)
  684.       goto noname;
  685.     mid--; /* the last below was it */
  686.   }
  687.   if (mid < 0)
  688.     goto noname;
  689.   if (strcmp(syms[mid].name, "_end") == 0)
  690.     goto noname;
  691.   if (strcmp(syms[mid].name, "__end") == 0)
  692.     goto noname;
  693.   if (strcmp(syms[mid].name, "_etext") == 0)
  694.     goto noname;
  695.   if (delta)
  696.     *delta = val - syms[mid].address;
  697.   return syms[mid].name;
  698. noname:
  699.   sprintf(noname_buf, "%#lx", val);
  700.   return noname_buf;
  701. }
  702.  
  703. char *syms_val2line(word32 val, int *lineret, int exact)
  704. {
  705.   int f, l;
  706.   for (f=0; f<num_files; f++)
  707.   {
  708.     if (val >= files[f].first_address && val <= files[f].last_address && files[f].lines)
  709.     {
  710.       for (l=files[f].num_lines-1; l >= 0 && files[f].lines[l].l_addr.l_paddr > val; l--);
  711.       if ((files[f].lines[l].l_addr.l_paddr != val) && exact)
  712.         return 0;
  713.       *lineret = files[f].lines[l].l_lnno;
  714.       return files[f].filename;
  715.     }
  716.   }
  717.   return 0;
  718. }
  719.  
  720. void syms_listwild(char *pattern)
  721. {
  722.   int linecnt = 0;
  723.   int lnum;
  724.   char *name;
  725.   int i, key;
  726.  
  727.   for (i=0; i<num_syms; i++)
  728.     if (wild(pattern, syms_byname[i]))
  729.     {
  730.       if (++linecnt > 20)
  731.       {
  732.         printf("--- More ---");
  733.         fflush(stdout);
  734.         key = getkey();
  735.         printf("\r            \r");
  736.         switch (key)
  737.         {
  738.       case ' ':
  739.           linecnt = 0;
  740.         break;
  741.       case 13:
  742.         linecnt--;
  743.         break;
  744.       case 'q':
  745.       case 27:
  746.         return;
  747.         }
  748.       }
  749.       printf("0x%08lx %c %s", syms_byname[i].address, syms_byname[i].type_c, syms_byname[i].name);
  750.       name = syms_val2line(syms_byname[i].address, &lnum, 0);
  751.       if (name)
  752.         printf(", line %d of %s", lnum, name);
  753.       putchar('\n');
  754.     }
  755. }
  756.  
  757. #endif
  758.